package com.tjbank.cssys.tools.redis.mock;


import com.tjbank.cssys.framework.base.util.ApplicationContextHelper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


/**
 * Copyright © 天阳宏业科技股份有限公司 - All Rights Reserved
 *
 * @description:
 * @author: <a href="mailto:guzheng01@tansun.com.cn>Joey Gu</a>
 * @date: 2020-05-07 20:13
 **/
@Service
@Slf4j
public class MockUserServiceImpl implements MockUserService {
    /*
     * 模拟数据库
     */
    private static final Map<Long, MockUser> DATABASES = new HashMap<>();

    /*
     * 初始化数据
     */
    static {
        DATABASES.put(1L, new MockUser(1L, "user1"));
        DATABASES.put(2L, new MockUser(2L, "user2"));
        DATABASES.put(3L, new MockUser(3L, "user3"));
    }

    @Cacheable(value = "TTL60s", keyGenerator = "keyGenerator")
    @Override
    public List<MockUser> findByName(String name) {
        List<MockUser> result = new ArrayList<>();
        DATABASES.forEach((k, v) -> {
            if (v.getName().contains(name)) {
                result.add(v);
            }
        });

        return result;
    }

    /*
     * 此注解类的含义:
     * 新增用户完成后,如果结果不为null则将结果缓存至redis,因为数据库已经发生
     * 改变,原先findAll方法缓存的数据已经不是最新数据,则需要清除已缓存的结果
     * 待下次查询后再将数据库中最新的数据缓存至redis中,保证数据的一致性.
     *
     */
    @Caching(
        put = {
            @CachePut(value = "mockUser", key = "#result.id", condition = "#result != null")
        }
        ,evict = {
            @CacheEvict(value = "mockUser", key = "T(java.lang.String).format('%s_%s', #root.targetClass.simpleName, 'findAll')")
        }
    )
    @Override
    public MockUser saveOrUpdate(MockUser user) {
        DATABASES.put(user.getId(), user);
        return user;
    }

    /*
     * 如果缓存中没有内容则将整个方法查询的内容缓存到Redis中
     */
    @Override
    @Cacheable(value = "mockUser", keyGenerator = "keyGenerator")
    public List<MockUser> findAll() {
        log.debug("查询所有数据:{}", DATABASES.size());
        return new ArrayList<>(DATABASES.values());
    }

    @Override
    @Cacheable(value = "mockUser", key = "#id")
    public MockUser get(Long id) {
        // 我们假设从数据库读取
        log.info("查询用户【id】= {}", id);
        return DATABASES.get(id);
    }

    @Override
    @Caching(
        evict = {
            @CacheEvict(value = "mockUser", key = "#id"),
            @CacheEvict(value = "mockUser", key = "T(java.lang.String).format('%s_%s', #root.targetClass.simpleName, 'findAll')")
        }
    )
    public void delete(Long id) {
        DATABASES.remove(id);
        log.info("删除用户【id】= {}", id);
    }

    /**
     * 要通过代理方式才能使cache注解生效.
     *
     * @param user user对象
     * @return 对象
     */
    @Override
    public MockUser composeOper(MockUser user) {
        // 删除旧数据
        // ((MockUserService) AopContext.currentProxy()).delete(user.getId());
        MockUserService mockUserService = ApplicationContextHelper.getBean(MockUserService.class);
        log.debug(">>>{}", mockUserService);
        mockUserService.delete(user.getId());
        // 增加新数据
        MockUser newUser = new MockUser(101L, "mooooock");
        // ((MockUserService) AopContext.currentProxy()).saveOrUpdate(newUser); // 待调通
        // this.saveOrUpdate(newUser); // 这样使用只能改变数据库,无法同步Redis
        mockUserService.saveOrUpdate(newUser);
        return user;
    }
}
